﻿using System;
using System.Collections.Generic;
using System.Linq;
using Abmemunit.Domain.Users;
using Abmemunit.Data.Infrastructure;
using System.Web.Security;
using System.Web;
using Abmemunit.Services.Security;

namespace Abmemunit.Services.Users
{
    /// <summary>
    /// User service
    /// </summary>
    public partial class UserService : IUserService
    {
        #region Constants
        private const string Passwordformate = "SHA1";
        #endregion Constants

        #region Fields

        private readonly IRepository<User> _userRepository;
        private readonly IRepository<UserRole> _roleRepository;
        private IEncryptionService _encryptionService;
        private HttpContextBase _httpContext;

        #endregion Fields

        #region Ctor
        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="userRepository"></param>
        /// <param name="roleRepository"></param>
        /// <param name="httpContext"></param>
        public UserService(IRepository<User> userRepository, IRepository<UserRole> roleRepository,  IEncryptionService encryptionService, HttpContextBase httpContext)
        {
            this._userRepository = userRepository;
            this._encryptionService = encryptionService;
            this._httpContext = httpContext;
            _roleRepository = roleRepository;
        }

        #endregion Ctor

        #region Methods

        /// <summary>
        /// gets a User by user name
        /// </summary>
        /// <param name="userName"></param>
        /// <returns>A user</returns>
        public User GetUserByName(string userName)
        {
            if (string.IsNullOrWhiteSpace(userName))
                return null;

            var query = from c in _userRepository.Table
                        orderby c.Id
                        where c.Username == userName
                        select c;
            var user = query.FirstOrDefault();
            return user;


        }

        /// <summary>
        /// gets a user by email
        /// </summary>
        /// <param name="email"></param>
        /// <returns>A user</returns>
        public User GetUserByEmail(string email)
        {
            if (string.IsNullOrWhiteSpace(email))
                return null;

            var query = from c in _userRepository.Table
                        orderby c.Id
                        where c.Email == email
                        select c;
            var user = query.FirstOrDefault();
            return user;


        }

        /// <summary>
        /// gets a User by id
        /// </summary>
        /// <param name="userId"></param>
        /// <returns>A User</returns>
        public User GetUserById(int userId)
        {
            if (userId == 0)
                return null;

            var user = _userRepository.GetById(userId);
            return user;

            //var user = _userRepository.Get(x => x.Id == id);
            //return user;
        }

        /// <summary>
        /// gets all users
        /// </summary>
        /// <returns>All users</returns>
        public IEnumerable<User> GetUsers()
        {
            var user = _userRepository.Table.ToList();
            return user;
        }


        /// <summary>
        /// Creates new User
        /// </summary>
        /// <param name="user"></param>
        public void CreateUser(User user)
        {

            var query = from c in _userRepository.Table
                        orderby c.Id
                        where c.Username == user.Username
                        select c;
            var retUser = query.FirstOrDefault();
            if (retUser == null)
            {

                string pwd = "";
                string saltKey = _encryptionService.CreateSaltKey(5);
                pwd = _encryptionService.CreatePasswordHash(user.Password, saltKey);
                user.Password = pwd;
                user.PasswordSalt = saltKey;
                UserRole userRole = null;
                if (user.IsAdminAccount)
                {
                    userRole = GetUserRoleByRoleName(UserRoleNames.Administrators);
                }
                else
                {
                    userRole = GetUserRoleByRoleName(UserRoleNames.Members);
                }
                user.UserRoles.Add(userRole);
                _userRepository.Insert(user);
                SaveUser();
            }


        }

        /// <summary>
        /// Delete user
        /// </summary>
        /// <param name="id"></param>
        public void DeleteUser(int id)
        {
            var delUser = _userRepository.GetById(id);
            if (delUser!=null)
            {
                _userRepository.Delete(delUser);
                SaveUser();
            }
            
        }


        /// <summary>
        /// Update User
        /// </summary>
        /// <param name="user"></param>
        public void UpdateUser(User user)
        {
            if (user != null)
            {
                _userRepository.Update(user);
                
                SaveUser();
            }
        }


        /// <summary>
        /// Commits pending changes
        /// </summary>
        public void SaveUser()
        {
            //_unitOfWork.Commit();
            _userRepository.SaveChanges();
        }


        /// <summary>
        /// Checks user validity
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public virtual bool ValidateUser(User user)
        {
            User dbUser = null;
            dbUser = GetUserByName(user.Username);
            if (dbUser == null )
                return false;

            string pwd = "";

            ////string saltKey = _encryptionService.CreateSaltKey(5);
            pwd = _encryptionService.CreatePasswordHash(user.Password, dbUser.PasswordSalt);

            bool isValid = pwd == dbUser.Password;

            //save last login date
            if (isValid)
            {
                user.LastLoginDateUtc = DateTime.UtcNow;
                UpdateUser(dbUser);
            }


            return isValid;
        }

        /// <summary>
        /// Signin User
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="user"></param>
        /// <param name="createPersistentCookie"></param>
        public virtual void SignIn(HttpContextBase httpContext, User user, bool createPersistentCookie)
        {
            var now = DateTime.UtcNow.ToLocalTime();
            TimeSpan expirationTimeSpan = FormsAuthentication.Timeout;
            var ticket = new FormsAuthenticationTicket(
                1 /*version*/,
                user.Username,
                now,
                now.Add(expirationTimeSpan),
                createPersistentCookie,
                user.Username,
                FormsAuthentication.FormsCookiePath);

            var encryptedTicket = FormsAuthentication.Encrypt(ticket);

            var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
            cookie.HttpOnly = true;
            if (ticket.IsPersistent)
            {
                cookie.Expires = ticket.Expiration;
            }
            cookie.Secure = FormsAuthentication.RequireSSL;
            cookie.Path = FormsAuthentication.FormsCookiePath;
            if (FormsAuthentication.CookieDomain != null)
            {
                cookie.Domain = FormsAuthentication.CookieDomain;
            }
            
            this._httpContext = httpContext;
            _httpContext.Response.Cookies.Add(cookie);
        }

        /// <summary>
        /// Sign out
        /// </summary>
        public virtual void SignOut()
        {
            FormsAuthentication.SignOut();
        }



        #endregion Methods

        #region UserRole
        public UserRole GetUserRoleByRoleName(string roleName)
        {
            var queryRole = from c in _roleRepository.Table
                            where c.Name == roleName
                            select c;
            var userRole = queryRole.FirstOrDefault();
            return userRole;

        }
        #endregion
    }
}
